/**
 * @Author: Painter
 * @project_name: Java_Dome
 * @system_login: sunshine
 * @time: 2022-06-29-0029  22:23
 */

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import java.util.Random;
import java.util.Stack;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;

public class Chinesechese extends Canvas implements MouseListener {
    class Record {
        int fromx, fromy, tox, toy, fromindex, toindex;

        Record(int fromx, int fromy, int tox, int toy, int fromindex, int toindex) {
            this.fromx = fromx;
            this.fromy = fromy;
            this.tox = tox;
            this.toy = toy;
            this.fromindex = fromindex;
            this.toindex = toindex;
        }
    }

    int take_x = -1, take_y = -1, player = 0;
    boolean isRuning = true;
    int table[][] = new int[10][11];
    String name[] = {"", "将", "仕", "像", "傌", "俥", "炮", "卒", "帅", "士", "相", "马", "车", "炮", "兵"};
    int value[] = {0, 1000, 30, 30, 50, 200, 100, 30, -1000, -30, -30, -50, -200, -100, -30};
    int init_table[] = {0, 5, 4, 3, 2, 1, 2, 3, 4, 5};
    Random radom = new Random();
    BufferedImage map = new BufferedImage(500, 600, BufferedImage.TYPE_INT_RGB);
    BufferedImage offScreenImage = new BufferedImage(500, 600, BufferedImage.TYPE_INT_RGB);
    BufferedImage runImage = new BufferedImage(500, 600, BufferedImage.TYPE_INT_RGB);
    Stack<Record> recordstk = new Stack<Record>();

    Chinesechese() {
        this.addMouseListener(this);
        this.setBounds(150, 0, 500, 600);
        this.setBackground(Color.BLACK);
        Graphics g = map.getGraphics();
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, 500, 570);
        g.setColor(Color.black);
        g.setFont(new Font("Dialog", 0, 35));
        g.drawString(" 楚河         汉界", 130, 285);
        for (int i = 0; i < 9; i++) {
            g.drawLine(i * 50 + 50, 30 + 10, i * 50 + 50, 230 + 10);
            g.drawLine(i * 50 + 50, 300 + 10, i * 50 + 50, 500 + 10);
        }
        for (int i = 0; i < 5; i++) g.drawLine(50, 30 + i * 50 + 10, 450, 30 + i * 50 + 10);
        for (int i = 0; i < 5; i++) g.drawLine(50, 300 + i * 50 + 10, 450, 300 + i * 50 + 10);
        g.drawLine(50, 230, 50, 330);
        g.drawLine(450, 230, 450, 330);
        g.drawLine(200, 30 + 10, 300, 130 + 10);
        g.drawLine(200, 130 + 10, 300, 30 + 10);
        g.drawLine(200, 400 + 10, 300, 500 + 10);
        g.drawLine(200, 500 + 10, 300, 400 + 10);
        for (int i = 0; i < 10; i++) table[i][1] = init_table[i];
        for (int i = 0; i < 10; i++) table[i][10] = init_table[i] + 7;
        for (int i = 1; i < 10; i += 2) table[i][4] = 7;
        for (int i = 1; i < 10; i += 2) table[i][7] = 14;
        table[2][3] = table[8][3] = 6;
        table[2][8] = table[8][8] = 13;
        paintTable();
    }

    public void paint(Graphics g) {
        g.drawImage(offScreenImage, 0, 0, 500, 600, this);
    }

    void paintTable() {
        Graphics g = offScreenImage.getGraphics();
        g.drawImage(map, 0, 0, 500, 600, this);
        for (int h = 1; h <= 10; h++)
            for (int w = 1; w < 10; w++) {
                if (table[w][h] == 0) continue;
                if (h <= 5) {
                    g.setColor(Color.white);
                    g.fillArc(w * 50 - 25, h * 50 - 35, 50, 50, 0, 360);
                    if (table[w][h] <= 7) g.setColor(Color.green);
                    else g.setColor(Color.red);
                    g.drawArc(w * 50 - 25, h * 50 - 35, 50, 50, 0, 360);
                    g.drawArc(w * 50 - 25 + 5, h * 50 - 35 + 5, 40, 40, 0, 360);
                    g.setFont(new Font("Dialog", 0, 35));
                    g.drawString(name[table[w][h]], w * 50 - 18, h * 50 + 2);
                } else {
                    g.setColor(Color.white);
                    g.fillArc(w * 50 - 25, h * 50 - 15, 50, 50, 0, 360);
                    if (table[w][h] <= 7) g.setColor(Color.green);
                    else g.setColor(Color.red);
                    g.drawArc(w * 50 - 25, h * 50 - 15, 50, 50, 0, 360);
                    g.drawArc(w * 50 - 20, h * 50 - 10, 40, 40, 0, 360);
                    g.setFont(new Font("Dialog", 0, 35));
                    g.drawString(name[table[w][h]], w * 50 - 18, h * 50 + 22);
                }
            }
    }

    void run(int startx, int starty, int endx, int endy, int index) {
        int k = Math.abs(endx - startx) * 5 + Math.abs(endy - starty) * 5;
        startx = startx * 50 - 25;
        if (starty <= 5) starty = starty * 50 - 35;
        else starty = starty * 50 - 15;
        endx = endx * 50 - 25;
        if (endy <= 5) endy = endy * 50 - 35;
        else endy = endy * 50 - 15;
        Graphics tg = runImage.getGraphics();
        Graphics g = this.getGraphics();
        paintTable();
        for (int i = 1; i <= k; i++) {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            int x = (-startx + endx) / k * i + startx;
            int y = (-starty + endy) / k * i + starty;
            tg.drawImage(offScreenImage, 0, 0, 500, 600, this);
            tg.setColor(Color.white);
            tg.fillArc(x, y, 50, 50, 0, 360);
            if (index <= 7) tg.setColor(Color.green);
            else tg.setColor(Color.red);
            tg.drawArc(x, y, 50, 50, 0, 360);
            tg.drawArc(x + 5, y + 5, 40, 40, 0, 360);
            tg.setFont(new Font("Dialog", 0, 35));
            tg.drawString(name[index], x + 7, y + 37);
            g.drawImage(runImage, 0, 0, 500, 600, this);
        }
        int x = endx;
        int y = endy;
        tg.drawImage(offScreenImage, 0, 0, 500, 600, this);
        tg.setColor(Color.white);
        tg.fillArc(x, y, 50, 50, 0, 360);
        if (index <= 7) tg.setColor(Color.green);
        else tg.setColor(Color.red);
        tg.drawArc(x, y, 50, 50, 0, 360);
        tg.drawArc(x + 5, y + 5, 40, 40, 0, 360);
        tg.setFont(new Font("Dialog", 0, 35));
        tg.drawString(name[index], x + 7, y + 37);
        g.drawImage(runImage, 0, 0, 500, 600, this);
    }

    int getnum(int sx, int sy, int ex, int ey) {
        int cnt = 0, t;
        cnt -= (table[sx][sy] == 0) ? 0 : 1;
        cnt -= (table[ex][ey] == 0) ? 0 : 1;
        if (sx > ex) {
            t = sx;
            sx = ex;
            ex = t;
        }
        if (sy > ey) {
            t = sy;
            sy = ey;
            ey = t;
        }
        for (int i = sx; i <= ex; i++)
            for (int j = sy; j <= ey; j++)
                cnt += (table[i][j] == 0) ? 0 : 1;
        return cnt;
    }

    boolean canmove(int sx, int sy, int ex, int ey) {
        if (sx == ex && sy == ey || table[sx][sy] == 0 || table[ex][ey] != 0 && table[ex][ey] / 8 == table[sx][sy] / 8)
            return false;
        if (table[sx][sy] % 7 == 1 && table[ex][ey] % 7 == 1 && Math.abs(ex - sx) == 0 && getnum(ex, ey, sx, sy) == 0)
            return true;
        switch (table[sx][sy]) {
            case 1:
                return ex > 3 && ex < 7 && ey < 4 && Math.abs(ex - sx) + Math.abs(ey - sy) == 1;
            case 2:
                return ex > 3 && ex < 7 && ey < 4 && Math.abs(ex - sx) == 1 && Math.abs(ey - sy) == 1;
            case 3:
                return ey < 6 && Math.abs(ex - sx) == 2 && Math.abs(ey - sy) == 2 && table[(ex + sx) / 2][(sy + ey) / 2] == 0;
            case 4:
                return Math.abs(ex - sx) == 2 && Math.abs(ey - sy) == 1 && table[(ex + sx) / 2][sy] == 0 ||
                        Math.abs(ex - sx) == 1 && Math.abs(ey - sy) == 2 && table[sx][(ey + sy) / 2] == 0;
            case 5:
                return (Math.abs(ex - sx) == 0 || Math.abs(ey - sy) == 0) && getnum(ex, ey, sx, sy) == 0;
            case 6:
                return (Math.abs(ex - sx) == 0 || Math.abs(ey - sy) == 0) &&
                        (table[ex][ey] != 0 && getnum(ex, ey, sx, sy) == 1 || table[ex][ey] == 0 && getnum(ex, ey, sx, sy) == 0);
            case 7:
                return ey < 6 && Math.abs(ex - sx) == 0 && ey - sy == 1 || ey >= 6 && Math.abs(ex - sx) + Math.abs(ey - sy) == 1 && ey >= sy;
        }
        switch (table[sx][sy] - 7) {
            case 1:
                return ex > 3 && ex < 7 && ey > 7 && Math.abs(ex - sx) + Math.abs(ey - sy) == 1;
            case 2:
                return ex > 3 && ex < 7 && ey > 7 && Math.abs(ex - sx) == 1 && Math.abs(ey - sy) == 1;
            case 3:
                return ey > 5 && Math.abs(ex - sx) == 2 && Math.abs(ey - sy) == 2 && table[(ex + sx) / 2][(sy + ey) / 2] == 0;
            case 4:
                return Math.abs(ex - sx) == 2 && Math.abs(ey - sy) == 1 && table[(ex + sx) / 2][sy] == 0 ||
                        Math.abs(ex - sx) == 1 && Math.abs(ey - sy) == 2 && table[sx][(ey + sy) / 2] == 0;
            case 5:
                return (Math.abs(ex - sx) == 0 || Math.abs(ey - sy) == 0) && getnum(ex, ey, sx, sy) == 0;
            case 6:
                return (Math.abs(ex - sx) == 0 || Math.abs(ey - sy) == 0) &&
                        (table[ex][ey] != 0 && getnum(ex, ey, sx, sy) == 1 || table[ex][ey] == 0 && getnum(ex, ey, sx, sy) == 0);
            case 7:
                return ey > 5 && Math.abs(ex - sx) == 0 && ey - sy == -1 || ey < 6 && Math.abs(ex - sx) + Math.abs(ey - sy) == 1 && ey <= sy;
        }
        return false;
    }

    int AImovefour() {
        int re = 0;
        for (int w = 1; w < 10; w++)
            for (int h = 1; h < 11; h++)
                if (table[w][h] > 7) {
                    for (int x = 1; x < 10; x++)
                        for (int y = 1; y < 11; y++)
                            if (canmove(w, h, x, y)) {
                                int t = table[x][y];
                                if (table[x][y] == 1) return -3000;
                                int score = -value[t];
                                if (score < re) re = score;
                            }
                }
        return re;
    }

    int AImovethree() {
        int re = -3000;
        for (int w = 1; w < 10; w++)
            for (int h = 1; h < 11; h++)
                if (table[w][h] > 0 && table[w][h] < 8) {
                    for (int x = 1; x < 10; x++)
                        for (int y = 1; y < 11; y++)
                            if (canmove(w, h, x, y)) {
                                if (table[x][y] == 8) return 3000;
                                int t = table[x][y];
                                table[x][y] = table[w][h];
                                table[w][h] = 0;
                                int score = -value[t] + AImovefour();
                                if (score > re && score + value[t] != -3000) re = score;
                                table[w][h] = table[x][y];
                                table[x][y] = t;
                            }
                }
        return re;
    }

    int AImovetwo() {
        int re = 3000;
        for (int w = 1; w < 10; w++)
            for (int h = 1; h < 11; h++)
                if (table[w][h] > 7) {
                    for (int x = 1; x < 10; x++)
                        for (int y = 1; y < 11; y++)
                            if (canmove(w, h, x, y)) {
                                if (table[x][y] == 1) return -3000;
                                int t = table[x][y];
                                table[x][y] = table[w][h];
                                table[w][h] = 0;
                                int score = -value[t] + AImovethree();
                                if (score < re && score + value[t] != 3000) re = score;
                                table[w][h] = table[x][y];
                                table[x][y] = t;
                            }
                }
        return re;
    }

    void AImove() {
        int take_x = 0, take_y = 0, q_x = 0, q_y = 0, maxval = -3000;
        int flag = 0;
        for (int w = 1; w < 10; w++) {
            for (int h = 1; h < 11; h++)
                if (table[w][h] > 0 && table[w][h] < 8) {
                    for (int x = 1; x < 10; x++) {
                        for (int y = 1; y < 11; y++)
                            if (canmove(w, h, x, y)) {
                                int movenum = 0;
                                for (int i = 1; i < 10; i++)
                                    for (int j = 1; j < 11; j++)
                                        if (canmove(w, h, i, j))
                                            movenum -= value[table[i][j]] / 10 + 1;
                                int t = table[x][y];
                                table[x][y] = table[w][h];
                                table[w][h] = 0;
                                int score = -value[t] + AImovetwo();
                                table[w][h] = table[x][y];
                                table[x][y] = t;
                                for (int i = 1; i < 10; i++)
                                    for (int j = 1; j < 11; j++)
                                        if (canmove(x, y, i, j))
                                            movenum += value[table[i][j]] / 10 + 1;
                                if (score + movenum >= maxval && score + value[t] != -3000) {
                                    if (score + movenum > maxval || radom.nextBoolean()) {
                                        maxval = score + movenum;
                                        take_x = w;
                                        take_y = h;
                                        q_x = x;
                                        q_y = y;
                                    }
                                }
                                if (t == 8) {
                                    maxval = 3000;
                                    flag = 1;
                                    take_x = w;
                                    take_y = h;
                                    q_x = x;
                                    q_y = y;
                                    break;
                                }

                            }
                        if (flag == 1) break;
                    }
                    if (flag == 1) break;
                }
            if (flag == 1) break;
        }
        if (maxval <= -3000) {
            JOptionPane.showMessageDialog(null, "你赢了");
            isRuning = false;
        } else {
            if (maxval >= 3000) {
                JOptionPane.showMessageDialog(null, "你输了");
                isRuning = false;
            }
            int index = table[take_x][take_y];
            table[take_x][take_y] = 0;
            recordstk.push(new Record(take_x, take_y, q_x, q_y, index, table[q_x][q_y]));
            run(take_x, take_y, q_x, q_y, index);
            table[q_x][q_y] = index;
            paintTable();
        }
    }

    public static void main(String[] args) {
        JFrame gameFrame = new JFrame("中国象棋");
        JButton regame = new JButton("重新开始");
        JButton retake = new JButton("悔棋");
        JButton complay = new JButton("电脑出手");
        Chinesechese chinesechese = new Chinesechese();
        retake.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {

                if (chinesechese.recordstk.empty()) JOptionPane.showMessageDialog(null, "无法再次悔棋");
                else {
                    for (int i = 0; i < 2; i++) {
                        Chinesechese.Record record = chinesechese.recordstk.pop();
                        chinesechese.table[record.tox][record.toy] = record.toindex;
                        chinesechese.paintTable();
                        chinesechese.run(record.tox, record.toy, record.fromx, record.fromy, record.fromindex);
                        chinesechese.table[record.fromx][record.fromy] = record.fromindex;
                        chinesechese.take_x = chinesechese.take_y = -1;
                        chinesechese.paintTable();
                        chinesechese.repaint();
                    }

                }
            }
        });
        regame.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                while (chinesechese.recordstk.empty() == false) {
                    Chinesechese.Record record = chinesechese.recordstk.pop();
                    chinesechese.table[record.tox][record.toy] = record.toindex;
                    chinesechese.paintTable();
                    chinesechese.run(record.tox, record.toy, record.fromx, record.fromy, record.fromindex);
                    chinesechese.table[record.fromx][record.fromy] = record.fromindex;
                    chinesechese.take_x = chinesechese.take_y = -1;
                    chinesechese.paintTable();
                    chinesechese.repaint();
                }
                chinesechese.isRuning = true;
            }
        });
        complay.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                chinesechese.AImove();
            }
        });
        regame.setBounds(670, 450, 100, 50);
        retake.setBounds(670, 350, 100, 50);
        complay.setBounds(670, 250, 100, 50);
        gameFrame.setBounds(100, 100, 800, 600);
        gameFrame.setLayout(null);
        gameFrame.add(chinesechese);
        gameFrame.add(regame);
        gameFrame.add(retake);
        gameFrame.add(complay);
        gameFrame.setVisible(true);
        gameFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    public void mouseClicked(MouseEvent e) {
        // TODO Auto-generated method stub

    }

    @Override
    public void mousePressed(MouseEvent e) {
        int x = e.getX();
        int y = e.getY();
        int q_x = -1, q_y = -1;
        if (y <= 265) {
            q_y = (y + 35) / 50;
            q_x = (x + 25) / 50;
        }
        if (y >= 285) {
            q_y = (y + 15) / 50;
            q_x = (x + 25) / 50;
        }
        if (q_x > 9 || q_y > 10 || q_x < 1 || q_y < 1) {
            q_x = -1;
            q_y = -1;
        }
        if (q_x != -1 && q_y != -1 && isRuning) {
            if (take_x != -1) {
                if (table[take_x][take_y] > 0 && canmove(take_x, take_y, q_x, q_y)) {
                    int index = table[take_x][take_y];
                    table[take_x][take_y] = 0;
                    recordstk.push(new Record(take_x, take_y, q_x, q_y, index, table[q_x][q_y]));
                    run(take_x, take_y, q_x, q_y, index);
                    take_x = -1;
                    take_y = -1;
                    table[q_x][q_y] = index;
                    Graphics g = this.getGraphics();
                    g.fillRect(100, 220, 300, 100);
                    g.setColor(Color.green);
                    g.setFont(new Font("Dialog", 0, 35));
                    g.drawString(" 等待绿方下棋 ", 130, 285);
                    paintTable();
                    AImove();
                } else {
                    take_x = -1;
                    take_y = -1;
                    paintTable();
                    repaint();
                }
            } else if (table[q_x][q_y] != 0 && take_x == -1) {
                take_x = q_x;
                take_y = q_y;
                Graphics g = offScreenImage.getGraphics();
                g.setColor(Color.BLACK);
                if (take_y <= 5) g.drawRect(take_x * 50 - 25, take_y * 50 - 35, 50, 50);
                else g.drawRect(take_x * 50 - 25, take_y * 50 - 15, 50, 50);
                g.setColor(Color.gray);
                for (int w = 1; w < 10; w++)
                    for (int h = 1; h < 11; h++) {
                        if (canmove(take_x, take_y, w, h)) {
                            if (h <= 5) g.drawRect(w * 50 - 20, h * 50 - 30, 40, 40);
                            else g.drawRect(w * 50 - 20, h * 50 - 10, 40, 40);
                        }
                    }
                repaint();
            }

        }
    }

    public void mouseReleased(MouseEvent e) {
        // TODO Auto-generated method stub

    }

    public void mouseEntered(MouseEvent e) {
        // TODO Auto-generated method stub

    }

    public void mouseExited(MouseEvent e) {
        // TODO Auto-generated method stub

    }
}

